#include "aerial\Scene\SceneManager.h"

#include "aerial\Scene\Scene.h"
#include "aerial\Scene\Event.h"

#include "aerial\Object\Object.h"

#include <iostream>

using namespace air;
using namespace std;

SceneManager::SceneManager(): 
	current(NULL), next(NULL),
	hge(NULL), gui(NULL), hgeResMan(NULL), netIO(NULL)
{
	memset(eventMap, 0, sizeof(eventMap));
}

SceneManager::~SceneManager()
{
	for (int i = 1; i <= lastGuiId; i++)
	{
		delete eventMap[i];
		eventMap[i] = 0;
	}
	delete current;
	delete gui;

	//acc will automatically be released. yeah~
}

/**
 * @brief initialize scene. pass HGE, hgeGUI, hgeResourceManager and SceneManager to scene and call scene's initialize callback.
 *
 * @param iScene pointer to scene to be initialized
 
 * @return whether initialization is successful
 */
bool SceneManager::initializeScene(IScene* iScene)
{
	// clear event binding
	for (int i = 1; i <= lastGuiId; i++)
	{
		delete eventMap[i];
		eventMap[i] = 0;
	}
	delete current;

	// release all non-gui object
	acc.clear();
	// all non-gui object
	delete gui;
	gui = new hgeGUI();

	// initialize next scene
	current = iScene;
	lastGuiId = 0;
	current->beforeInitialize(this, hge, gui, hgeResMan, netIO);
	if (!current->initialize())
	{
		delete current;
		return false;
	}
	else return true;
}

void SceneManager::addObject(IObject* iObj)
{
	acc.addObject(iObj);
}

int SceneManager::addGuiObject(IGuiObject* iGuiObject)
{
	iGuiObject->assignId(++lastGuiId);
	gui->AddCtrl(iGuiObject);
	return lastGuiId;
}

void SceneManager::bindGuiObjectEvent(int _id, Event* evnt)
{
	if (_id >= 99 || _id == 0) 
	{
		MessageBox(NULL, L"wrong id", L"A.I.R", MB_OK);
		return;
	}

	if (_id != 0) eventMap[_id] = evnt;
}

void SceneManager::start()
{
	if (current) current->Enter();
}

/**
 * @brief update current scene, works with animation and scene change
 *
 * @param dt
 *
 * @return false for continuing running. true for stop
 */
bool SceneManager::update(float dt)
{
	if (!current) return true;

	acc.Update(dt);
	current->update(dt);

	int id = gui->Update(dt);
	// scene change if id return -1
	if (id == -1)
	{
		if (next)
		{
			IScene* iScene = next;
			next = NULL;
			if (!initializeScene(iScene)) 
			{
				MessageBox(NULL, L"Scene shift error", L"A.I.R Error", MB_OK);
				return true;
			}
			gui->Enter();
		} else return true;
	} else if (id)
	{
		if (eventMap[id]) eventMap[id]->callback();
		currentGuiId = id;
	}
	return false;
}

bool SceneManager::render(float dt)
{
	current->render(dt);
	acc.Render();
	gui->Render();
	return false;
}
